/***************************************************************************
 *   This is a part of the NextCAD Web APP.                                *
 *   Copyright (C) AMCAX, All rights reserved.                             *
 ***************************************************************************/
import { Renderer3D, RendererMgr } from '@amcax/renderer';
import { wsApi } from '../../server/wsApi';
import { previewer } from '../../module';

export abstract class Interactor2<P> {
  private inTrans: boolean = false;
  private env: 'BIM' | 'CAD';
  protected params: P;

  constructor() {
    this.params = this.initParams();
  }

  initParams(): P {
    return null;
  }
  getExecuteParams(params: P): any {
    return null;
  }

  async begin(cmdName: string, env?: 'BIM' | 'CAD'): Promise<void> {
    this.env = env == undefined ? 'CAD' : env;
    if (!this.inTrans) {
      this.inTrans = true;
      await wsApi.startTransaction({
        n: cmdName,
        e: this.env,
      });
    }
  }

  async setArguments(object?: string | string[]) {
    if (object) {
      await wsApi.setArguments({
        o: object,
      });
    }
  }

  async execute(payload: Partial<P>): Promise<void> {
    Object.assign(this.params, payload);
    if (this.inTrans) {
      const cmd_params = this.getExecuteParams(this.params);
      if (cmd_params) {
        try {
          const result = await wsApi.executeTransaction({
            a: cmd_params,
            placement: cmd_params.placement || [],
            e: this.env,
          });
          this.preview(result);
        } catch (error) {
          console.log('execute failed', error);
        }
      }
    }
  }

  async abort() {
    if (this.inTrans) {
      let models: any;
      try {
        this.inTrans = false;
        models = await wsApi.abortTransaction({ e: this.env });
      } catch (err) {
        this.inTrans = true;
        throw err;
      }
      if (models?.created?.length > 0) {
        // ctx2.scene.updateOnScene(() => models?.created)
      }
      this.clearPriview();
    } else {
      console.warn(
        'Command abort failed, because it is not in transaction. Potential leak of transaction.',
      );
    }
  }

  async end() {
    if (this.inTrans) {
      try {
        this.inTrans = false;
        await wsApi.endTransaction({ e: this.env });
        this.clearPriview();
      } catch (err) {
        console.log('Command end failed', err);
        this.inTrans = true;
        throw err;
      }
    } else {
      console.warn(
        'Command end failed, because it is not in transaction. Potential leak of transaction.',
      );
    }
  }

  async preview(result: any) {
    if (result) {
      const models =
        await RendererMgr.getRender<Renderer3D>('3d').parsePreviewModels(
          result,
        );
      if (models?.length > 0) {
        previewer.preview(models);
      } else {
        console.log('预览模型渲染失败');
      }
    }
  }
  clearPriview() {
    previewer.clear();
  }

  destroy() {
    this.abort();
    this.clearPriview();
  }
}
